import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';

/// 🌐 Dio 网络请求工具类
///
/// 功能特性：
/// 1. 单例模式，全局统一配置
/// 2. 支持 GET/POST/PUT/DELETE 等 HTTP 方法
/// 3. 请求/响应拦截器
/// 4. 错误统一处理
/// 5. 文件上传/下载
/// 6. 请求取消功能
///
/// 使用示例：
/// ```dart
/// // GET 请求
/// var response = await DioUtil().get('/api/users');
///
/// // POST 请求
/// var response = await DioUtil().post('/api/login', data: {'username': 'admin'});
/// ```
class DioUtil {
  // 单例实例
  static final DioUtil _instance = DioUtil._internal();

  /// Dio 实例
  late Dio _dio;

  /// 默认连接超时时间
  static const Duration _defaultConnectTimeout = Duration(seconds: 10);

  /// 默认接收超时时间
  static const Duration _defaultReceiveTimeout = Duration(seconds: 10);

  /// 默认发送超时时间
  static const Duration _defaultSendTimeout = Duration(seconds: 10);

  /// 基础 URL
  static const String _baseUrl = 'https://api.yourserver.com/v1';

  /// 工厂构造函数，返回单例实例
  factory DioUtil() {
    return _instance;
  }

  /// 私有构造函数
  DioUtil._internal() {
    // 创建 Dio 实例并配置基础选项
    _dio = Dio(
      BaseOptions(
        // baseUrl: _baseUrl,
        connectTimeout: _defaultConnectTimeout,
        receiveTimeout: _defaultReceiveTimeout,
        sendTimeout: _defaultSendTimeout,

        // 默认请求头
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },

        // 响应类型
        responseType: ResponseType.json,

        // 验证状态码，当状态码不是 200-299 时抛出 DioException
        validateStatus: (status) {
          return status != null && status >= 200 && status < 300;
        },
      ),
    );

    // 添加拦截器
    _addInterceptors();
  }

  /// 🔧 添加拦截器
  void _addInterceptors() {
    // 添加日志拦截器
    _dio.interceptors.add(
      LogInterceptor(
        // 是否开启请求日志
        request: true,
        // 是否开启请求头日志
        requestHeader: true,
        // 是否开启请求体日志
        requestBody: true,
        // 是否开启响应头日志
        responseHeader: true,
        // 是否开启响应体日志
        responseBody: true,
        // 错误日志
        error: true,
        // 日志级别
        logPrint: (log) {
          // 使用 debugPrint 在调试控制台输出日志
          debugPrint('Dio Log: $log');
        },
      ),
    );

    // 添加自定义拦截器
    _dio.interceptors.add(
      InterceptorsWrapper(
        /// 📤 请求拦截器
        /// 在请求发送前被调用，可以在这里添加认证令牌、修改请求参数等
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
          // 打印请求信息
          debugPrint('🚀 发送请求: ${options.method} ${options.uri}');
          debugPrint('📦 请求数据 data : ${options.data}');
          debugPrint('📦 请求数据 queryParameters : ${options.queryParameters}');
          debugPrint('🔑 请求头: ${options.headers}');

          // 在这里可以添加认证令牌
          // 例如从本地存储获取 token
          // String? token = await _getToken();
          // if (token != null) {
          //   options.headers['Authorization'] = 'Bearer $token';
          // }

          // 继续请求
          return handler.next(options);
        },

        /// 📥 响应拦截器
        /// 在响应返回后被调用，可以在这里处理响应数据、错误等
        onResponse: (Response response, ResponseInterceptorHandler handler) {
          // 打印响应信息
          debugPrint(
            '✅ 收到响应: ${response.statusCode} ${response.requestOptions.uri}',
          );
          debugPrint('📨 响应数据: ${response.data}');

          // 在这里可以统一处理响应格式
          // 例如检查业务逻辑错误码
          // if (response.data['code'] != 0) {
          //   throw DioException(
          //     requestOptions: response.requestOptions,
          //     error: response.data['message'],
          //   );
          // }

          // 继续响应
          return handler.next(response);
        },

        /// ❌ 错误拦截器
        /// 在请求发生错误时被调用，可以在这里统一处理错误
        onError: (DioException error, ErrorInterceptorHandler handler) {
          // 打印错误信息
          debugPrint('❌ 请求错误: ${error.type} - ${error.message}');
          debugPrint(
            '🔧 错误详情: ${error.response?.statusCode} - ${error.response?.data}',
          );

          // 根据错误类型进行统一处理
          String errorMessage = _handleError(error);
          debugPrint('📝 错误信息: $errorMessage');

          // 可以在这里添加重试逻辑、token刷新等

          // 继续错误处理
          return handler.next(error);
        },
      ),
    );
  }

  /// 🛠️ 错误处理
  ///
  /// [error] Dio 错误对象
  ///
  /// 返回错误描述信息
  String _handleError(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return '网络连接超时，请检查网络设置';

      case DioExceptionType.badResponse:
        // 服务器返回了错误状态码
        return _handleStatusCode(error.response?.statusCode);

      case DioExceptionType.cancel:
        return '请求已被取消';

      case DioExceptionType.unknown:
        if (error.error?.toString().contains('SocketException') == true) {
          return '网络连接失败，请检查网络设置';
        }
        return '未知错误：${error.message}';

      case DioExceptionType.badCertificate:
        return '证书验证失败';

      case DioExceptionType.connectionError:
        return '网络连接错误';
    }
  }

  /// 🛠️ 处理 HTTP 状态码
  ///
  /// [statusCode] HTTP 状态码
  ///
  /// 返回状态码对应的错误信息
  String _handleStatusCode(int? statusCode) {
    switch (statusCode) {
      case 400:
        return '请求参数错误';
      case 401:
        return '未授权，请重新登录';
      case 403:
        return '访问被禁止';
      case 404:
        return '请求的资源不存在';
      case 405:
        return '请求方法不被允许';
      case 500:
        return '服务器内部错误';
      case 502:
        return '网关错误';
      case 503:
        return '服务不可用';
      default:
        return '服务器错误 ($statusCode)';
    }
  }

  /// ==================== 公共请求方法 ====================

  /// 📨 GET 请求
  ///
  /// [path] 请求路径
  /// [queryParameters] 查询参数
  /// [options] 请求选项
  /// [cancelToken] 取消令牌
  ///
  /// 返回响应数据
  Future<Response<T>> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response<T> response = await _dio.get<T>(
        path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📨 POST 请求
  ///
  /// [path] 请求路径
  /// [data] 请求数据
  /// [queryParameters] 查询参数
  /// [options] 请求选项
  /// [cancelToken] 取消令牌
  ///
  /// 返回响应数据
  Future<Response<T>> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response<T> response = await _dio.post<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📨 PUT 请求
  ///
  /// [path] 请求路径
  /// [data] 请求数据
  /// [queryParameters] 查询参数
  /// [options] 请求选项
  /// [cancelToken] 取消令牌
  ///
  /// 返回响应数据
  Future<Response<T>> put<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response<T> response = await _dio.put<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📨 DELETE 请求
  ///
  /// [path] 请求路径
  /// [data] 请求数据
  /// [queryParameters] 查询参数
  /// [options] 请求选项
  /// [cancelToken] 取消令牌
  ///
  /// 返回响应数据
  Future<Response<T>> delete<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response<T> response = await _dio.delete<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📨 PATCH 请求
  ///
  /// [path] 请求路径
  /// [data] 请求数据
  /// [queryParameters] 查询参数
  /// [options] 请求选项
  /// [cancelToken] 取消令牌
  ///
  /// 返回响应数据
  Future<Response<T>> patch<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response<T> response = await _dio.patch<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// ==================== 文件操作 ====================

  /// 📤 文件上传
  ///
  /// [path] 上传路径
  /// [filePath] 本地文件路径
  /// [name] 表单字段名
  /// [data] 其他表单数据
  /// [onSendProgress] 上传进度回调
  /// [cancelToken] 取消令牌
  ///
  /// 返回上传响应
  Future<Response<T>> uploadFile<T>(
    String path,
    String filePath, {
    String name = 'file',
    Map<String, dynamic>? data,
    ProgressCallback? onSendProgress,
    CancelToken? cancelToken,
  }) async {
    try {
      // 创建 FormData
      FormData formData = FormData.fromMap({
        ...?data,
        name: await MultipartFile.fromFile(filePath),
      });

      final Response<T> response = await _dio.post<T>(
        path,
        data: formData,
        onSendProgress: onSendProgress,
        cancelToken: cancelToken,
        options: Options(contentType: 'multipart/form-data'),
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📤 多文件上传
  ///
  /// [path] 上传路径
  /// [files] 文件列表，每个文件是 Map {'path': 文件路径, 'field': 字段名}
  /// [data] 其他表单数据
  /// [onSendProgress] 上传进度回调
  /// [cancelToken] 取消令牌
  ///
  /// 返回上传响应
  Future<Response<T>> uploadMultipleFiles<T>(
    String path,
    List<Map<String, String>> files, {
    Map<String, dynamic>? data,
    ProgressCallback? onSendProgress,
    CancelToken? cancelToken,
  }) async {
    try {
      // 创建文件列表
      List<MultipartFile> multipartFiles = [];

      for (var file in files) {
        String filePath = file['path']!;
        String fieldName = file['field'] ?? 'files';

        multipartFiles.add(
          await MultipartFile.fromFile(
            filePath,
            filename: filePath.split('/').last,
          ),
        );
      }

      // 创建 FormData
      FormData formData = FormData.fromMap({...?data, 'files': multipartFiles});

      final Response<T> response = await _dio.post<T>(
        path,
        data: formData,
        onSendProgress: onSendProgress,
        cancelToken: cancelToken,
        options: Options(contentType: 'multipart/form-data'),
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// 📥 文件下载
  ///
  /// [url] 下载地址
  /// [savePath] 保存路径
  /// [onReceiveProgress] 下载进度回调
  /// [cancelToken] 取消令牌
  ///
  /// 返回下载响应
  Future<Response> downloadFile(
    String url,
    String savePath, {
    ProgressCallback? onReceiveProgress,
    CancelToken? cancelToken,
  }) async {
    try {
      final Response response = await _dio.download(
        url,
        savePath,
        onReceiveProgress: onReceiveProgress,
        cancelToken: cancelToken,
      );
      return response;
    } on DioException {
      rethrow;
    }
  }

  /// ==================== 配置相关方法 ====================

  /// ⚙️ 更新基础 URL
  void updateBaseUrl(String baseUrl) {
    _dio.options.baseUrl = baseUrl;
  }

  /// ⚙️ 更新请求头
  void updateHeaders(Map<String, dynamic> headers) {
    _dio.options.headers.addAll(headers);
  }

  /// ⚙️ 设置认证令牌
  void setAuthToken(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }

  /// ⚙️ 清除认证令牌
  void clearAuthToken() {
    _dio.options.headers.remove('Authorization');
  }

  /// ⚙️ 获取当前的 Dio 实例（用于特殊需求）
  Dio get dio => _dio;

  /// ⚙️ 创建新的取消令牌
  CancelToken createCancelToken() {
    return CancelToken();
  }

  /// ⚙️ 取消所有请求
  void cancelAllRequests() {
    // Dio 5.x 版本需要手动管理 CancelToken
    // 这里可以维护一个 CancelToken 列表来实现批量取消
  }
}

/// 🌟 响应数据模型基类
///
/// 用于统一处理服务器响应格式
class BaseResponse<T> {
  /// 状态码
  final int code;

  /// 消息
  final String message;

  /// 数据
  final T? data;

  /// 是否成功
  bool get isSuccess => code == 0 || code == 200;

  BaseResponse({required this.code, required this.message, this.data});

  /// 从 JSON 创建 BaseResponse
  factory BaseResponse.fromJson(
    Map<String, dynamic> json,
    T Function(Object? json)? fromJsonT,
  ) {
    return BaseResponse<T>(
      code: json['code'] as int,
      message: json['message'] as String,
      data: fromJsonT != null ? fromJsonT(json['data']) : json['data'] as T?,
    );
  }

  @override
  String toString() {
    return 'BaseResponse{code: $code, message: $message, data: $data}';
  }
}

/// 📝 使用示例
class ApiService {
  static final DioUtil _dio = DioUtil();

  /// 获取用户列表
  static Future<List<User>> getUsers() async {
    try {
      final response = await _dio.get('/users');

      // 解析响应数据
      if (response.statusCode == 200) {
        List<dynamic> data = response.data['data'];
        return data.map((json) => User.fromJson(json)).toList();
      } else {
        throw Exception('Failed to load users');
      }
    } on DioException catch (e) {
      // 处理 Dio 错误
      throw Exception('Network error: ${e.message}');
    }
  }

  /// 用户登录
  static Future<User> login(String username, String password) async {
    try {
      final response = await _dio.post(
        '/login',
        data: {'username': username, 'password': password},
      );

      if (response.statusCode == 200) {
        // 保存 token
        String token = response.data['token'];
        _dio.setAuthToken(token);

        return User.fromJson(response.data['user']);
      } else {
        throw Exception('Login failed');
      }
    } on DioException catch (e) {
      throw Exception('Login error: ${e.message}');
    }
  }

  /// 上传头像
  static Future<String> uploadAvatar(String filePath) async {
    try {
      final response = await _dio.uploadFile(
        '/upload/avatar',
        filePath,
        name: 'avatar',
        onSendProgress: (sent, total) {
          print('上传进度: ${(sent / total * 100).toStringAsFixed(1)}%');
        },
      );

      if (response.statusCode == 200) {
        return response.data['url'];
      } else {
        throw Exception('Upload failed');
      }
    } on DioException catch (e) {
      throw Exception('Upload error: ${e.message}');
    }
  }
}

/// 👤 用户数据模型
class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(id: json['id'], name: json['name'], email: json['email']);
  }
}
